package cate.game.role.pvp.jungle;

import cate.common.table.d.GDFight;
import cate.common.table.d.GDFunc;
import cate.common.table.d.GDOperation;
import cate.common.table.jungle.task.JungleTaskRow;
import cate.common.util.GameResult;
import cate.common.util.TimeTool;
import cate.common.util.random.RWList;
import cate.game.play.part.FightSide;
import cate.game.play.proce.play.PlayPO;
import cate.game.pvp.jungle.JungleConstants;
import cate.game.pvp.jungle.core.*;
import cate.game.pvp.jungle.msg.*;
import cate.game.pvp.jungle.msg.JungleStartTaskReq;
import cate.game.res.MixRes;
import cate.game.res.MixResAdder;
import cate.game.res.MixResConsumer;
import cate.game.res.MixResItem;
import cate.game.role.Role;
import cate.game.role.RoleSnapshot;
import cate.game.role.farm.AbstractFarm;
import cate.game.role.fight.Position;
import cate.game.role.pvp.jungle.msg.*;
import cate.game.role.res.guild.po.GuildPO;
import cate.game.role.res.guild.po.member.GuildMemberDetailPO;
import com.fasterxml.jackson.annotation.JsonIgnore;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;
import easy.java.practice.errorcode.EcResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.annotation.Transient;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Slf4j
@NoteClass("丛林探险个人数据")
public class MyJunglePO extends AbstractFarm {
    @NoteField("当前任务ID")
    public int taskId;
    @NoteField("今日派遣次数")
    public int playTimes;
    @NoteField("今日掠夺次数")
    public int robTimes;
    @NoteField("已经结束的任务奖励")
    public JungleFinishReward fin;
    @NoteField("战报")
    public List<JungleRobReport> reports;
    @Transient
    @NoteField("正在进行的任务")
    public JungleTaskData current;

    @Transient
    @JsonIgnore
    @NoteField("前端是否在观看")
    public boolean viewing;

    @Override
    public void initialize(Role role) {
        super.initialize(role);
        if (reports == null) {
            reports = new ArrayList<>();
        }
    }

    @Override
    public void onEnter() {
        if (!isOpen()) {
            return;
        }
        if (taskId == 0) {
            normalRefresh();
        }
        current = game().pvp.jungle.getMyCurrentTask(role);
    }

    @Override
    public int getFuncId() {
        return GDFunc.JUNGLE;
    }

    @Override
    public int getFightFuncId() {
        return GDFunc.JUNGLE;
    }

    @Override
    public void onAfterOpen() {
        // 同布阵容
        role.getRes().crossSync.syncAdventure();
        normalRefresh();
        noticeUpdate();
    }

    @Override
    public void onDaySpan(boolean silence) {
        if (!isOpen()) {
            return;
        }
        playTimes = 0;
        robTimes = 0;
        if (!silence) {
            noticeUpdate();
        }
    }

    /**
     * 初始化发送
     */
    public void initSend() {
        noticeUpdate();
    }

    /**
     * 主消息通知前端
     */
    public void noticeUpdate() {
        if (!isOpen()) {
            return;
        }
        role.sendNow(new JungleMyMainInfoResp(this));
    }

    /**
     * 查看状态变更
     *
     * @param viewing 是否查看中
     */
    public void viewMain(boolean viewing) {
        if (!isOpen()) {
            return;
        }
        this.viewing = viewing;
        if (viewing) {
            sendOverall(game().pvp.jungle.viewOverall());
            sendBuffInfo(game().pvp.jungle.viewBuffs());
        }
    }

    /**
     * 发送任务概览信息
     *
     * @param vo 原始信息
     */
    public void sendOverall(JungleOverallVO vo) {
        if (!isOpen()) {
            return;
        }
        if (vo == null) {
            log.error("[MyJunglePO] 概览信息为空,大概率跨服未连接");
            return;
        }
        role.sendNow(new JungleTaskOverallResp(vo.tasks));
    }

    /**
     * 发送BUFF信息
     *
     * @param vo 原始信息
     */
    public void sendBuffInfo(JungleBuffVO vo) {
        if (!isOpen()) {
            return;
        }
        if (vo == null) {
            log.error("[MyJunglePO] BUFF信息为空,大概率跨服未连接");
            return;
        }
        role.sendNow(new JungleBuffInfoResp(vo.buffs));
    }

    /**
     * 查看任务详情
     *
     * @param targetUid 目标UID
     */
    public void viewDetail(String targetUid) {
        if (!isOpen()) {
            return;
        }
        JungleTaskDetailVO vo = game().pvp.jungle.viewDetail(targetUid);
        if (vo == null) {
            log.error("[MyJunglePO] 任务详情为空,大概率跨服未连接");
            return;
        }
        role.sendNow(new JungleTaskDetailResp(vo));
    }

    /**
     * 刷新任务品质
     *
     * @param direct 直达最高品质
     * @return 刷新结果
     */
    public GameResult<Void> refreshTask(boolean direct) {
        GameResult<Void> r = new GameResult<>();
        if (!isOpen()) {
            return r.fail("功能未开启");
        }
        if (taskId == game().table.jungle.task.getMaxId()) {
            return r.fail("已获取最高品质的任务,无需刷新");
        }
        if (playTimes >= JungleConstants.DAILY_PLAY_MAX) {
            return r.fail("今日派遣次数已耗尽");
        }
        if (fin != null) {
            return r.fail("请先领取上次派遣奖励");
        }
        if (current != null) {
            return r.fail("当前已有派遣任务");
        }
        MixRes cost;
        if (direct) {
            cost = new MixRes(JungleConstants.DIRECT_REFRESH_COST);
            GameResult<MixResItem> r_cost = cost.consumeCheck(role);
            if (!r_cost.ok()) {
                return r.fail(r_cost);
            }
            new MixResConsumer<Void>().res(cost)
                    .tips(true)
                    .operation(GDOperation.JUNGLE_REFRESH_COST, 1)
                    .exe(role);
            taskId = game().table.jungle.task.getMaxId();
        } else {
            cost = new MixRes(JungleConstants.NORMAL_REFRESH_COST);
            GameResult<MixResItem> r_cost = cost.consumeCheck(role);
            if (!r_cost.ok()) {
                return r.fail(r_cost);
            }
            new MixResConsumer<Void>().res(cost)
                    .tips(true)
                    .operation(GDOperation.JUNGLE_REFRESH_COST, 0)
                    .exe(role);
            if (!normalRefresh()) {
                return r.fail("ERROR!");
            }
            game().notice.message(role, "消耗钻石" + cost.getItemsCount());
        }
        checkTriggerCrossBuff();
        return r.success();
    }

    /**
     * 普通刷新
     *
     * @return 是否刷新成功
     */
    private boolean normalRefresh() {
        RWList<JungleTaskRow> rwList = new RWList<>();
        List<JungleTaskRow> rows = game().table.jungle.task.getList().stream()
                .filter(row -> row.id >= taskId)
                .collect(Collectors.toList());
        rwList.setup(rows);
        JungleTaskRow taskRow = rwList.get();
        if (taskRow == null) {
            return false;
        }
        taskId = taskRow.id;
        return true;
    }

    /**
     * 检测是否触发添加跨服BUFF
     */
    private void checkTriggerCrossBuff() {
        JungleTaskRow row = game().table.jungle.task.get(taskId);
        if (row == null || !row.triggerRandomBuff) {
            return;
        }
        // 发消息给跨服
        game().pvp.jungle.sendTriggerBuff(role);
    }

    /**
     * 派遣任务
     *
     * @return 派遣结果
     */
    public GameResult<Void> startTask(String supporterUid) {
        GameResult<Void> r = new GameResult<>();
        if (!isOpen()) {
            return r.fail("功能未开启");
        }
        if (current != null) {
            return r.fail("当前已有任务");
        }
        if (fin != null) {
            return r.fail("请先领取上次派遣奖励");
        }
        if (playTimes >= JungleConstants.DAILY_PLAY_MAX) {
            return r.fail("今日派遣次数已耗尽");
        }
        RoleSnapshot supporter = null;
        if (!StringUtils.isEmpty(supporterUid)) {
            GuildPO guild = role.getRes().guild.getGuild();
            if (guild == null) {
                return r.fail("协助失败!");
            }
            GuildMemberDetailPO member = guild.member.getMember(supporterUid);
            if (member == null) {
                return r.fail("找不到协助者");
            }
            supporter = member.it;
        }
        JungleStartTaskReq req = new JungleStartTaskReq(new RoleSnapshot(role), taskId, supporter);
        JungleStartTaskRet ret = game().pvp.jungle.startTask(req);
        if (ret == null) {
            return r.fail("跨服未准备完毕");
        }
        if (!ret.r.ok()) {
            return ret.r;
        }
        playTimes++;
        current = ret.taskData;
        role.getRes().crossSync.syncAdventure();
        role.getHistory().action.jungleTimes();
        if (current != null) {
            role.getHistory().action.jungleQualityTimes(current.taskId);
        }
        return r.success();
    }

    /**
     * 查看支援信息
     */
    public void supportInfo() {
        List<GuildMemberDetailPO> members = Optional.ofNullable(role.getRes().guild.getGuild()).map(guildPO -> guildPO.member.list).orElse(new ArrayList<>());
        List<String> uidList = members.stream().map(member -> member.it.uid).collect(Collectors.toList());
        List<String> busyList = game().pvp.jungle.supportBusy(uidList);
        role.sendNow(new JungleSupportResp(members.stream()
                .map(member -> new JungleSupporter(member.it, busyList.contains(member.it.uid)))
                .collect(Collectors.toList())));
    }

    /**
     * 消耗钻石加速任务
     *
     * @return 结果
     */
    public GameResult<Void> costSpeedUp() {
        GameResult<Void> r = new GameResult<>();
        if (!isOpen()) {
            return r.fail("功能未开启");
        }
        if (current == null) {
            return r.fail("当前没有派遣任务");
        }
        long min = (current.endTime - System.currentTimeMillis()) / TimeTool.TimeCons.MINUTE;
        if (min <= 0) {
            return r.fail("ERROR!");
        }
        MixRes cost = new MixRes(JungleConstants.SPEED_UP_COST_PER_MIN).multiply(min);
        GameResult<MixResItem> r_cost = cost.consumeCheck(role);
        if (!r_cost.ok()) {
            return r.fail(r_cost);
        }
        boolean success = game().pvp.jungle.speedUp(role);
        if (!success) {
            return r.fail("加速失败!");
        }
        cost.consume(role);
        return r.success();
    }

    /**
     * 处理结束事件
     *
     * @param fin 结束奖励
     */
    public void handleTaskFinish(JungleFinishReward fin) {
        this.fin = fin;
        if (role.getStatus().isOnline()) {
            // 结束默认当前任务就没了
            this.current = null;
            noticeUpdate();
        }
    }

    /**
     * 领取任务奖励
     *
     * @return 领取结果
     */
    public GameResult<Void> receiveReward() {
        GameResult<Void> r = new GameResult<>();
        if (!isOpen()) {
            return r.fail("功能未开启");
        }
        if (fin == null) {
            return r.fail("当前没有可领取奖励");
        }
        new MixResAdder().setRes(fin.reward)
                .setSendMailWhenFull(true)
                .setDialogReward(true)
                .setOperation(GDOperation.JUNGLE_TASK)
                .setOperationSub(fin.taskId)
                .exe(role);
        fin = null;
        taskId = 0;
        normalRefresh();
        return r.success();
    }

    /**
     * 发起掠夺
     *
     * @param targetUid 对方UID
     * @return 掠夺结果
     */
    public GameResult<Void> robTask(String targetUid) {
        GameResult<Void> r = new GameResult<>();
        if (!isOpen()) {
            return r.fail("功能未开启");
        }
        if (isFighting()) {
            return r.fail("正在战斗中");
        }
        if (role.getUid().equals(targetUid)) {
            return r.fail("抢自己??");
        }
        GuildPO guildPO = role.getRes().guild.getGuild();
        if (guildPO != null) {
            GuildMemberDetailPO member = guildPO.member.getMember(targetUid);
            if (member != null) {
                return r.fail("不可掠夺同公会成员");
            }
        }
        if (robTimes >= JungleConstants.DAILY_ROB_MAX) {
            return r.fail("今日掠夺次数已用完");
        }
        Position position = role.getFight().getPosition(GDFunc.ADVENTURE);
        if (position == null) {
            return r.fail("请先布阵主线阵容");
        }
        JungleRobReq robReq = new JungleRobReq(role.getUid(), targetUid);
        JungleRobRet robRet = game().pvp.jungle.robTask(robReq);
        if (robRet == null) {
            return r.fail("跨服未准备完毕");
        }
        if (!robRet.r.ok()) {
            return robRet.r;
        }
        JungleRobFTC context = new JungleRobFTC(role);
        context.setPositionApply(GDFunc.ADVENTURE);
        if (robRet.attackBuffs != null && robRet.attackBuffs.size() > 0) {
            robRet.attackBuffs.forEach(buffSkill -> context.param.sideA.skillAppend.addTeamSkill(buffSkill));
        }
        if (robRet.defendBuffs != null && robRet.defendBuffs.size() > 0) {
            robRet.defendBuffs.forEach(buffSkill -> context.param.sideB.skillAppend.addTeamSkill(buffSkill));
        }
        FightSide fightSideB = role.getGame().fight.side.createFightSideByPlaySide(GDFight.Team.B, robRet.playSide);
        EcResult<PlayPO> r_fight = role.getGame().play.startByRole(role, context, fightSideB);
        if (!r_fight.ok()) {
            return r.fail(r_fight);
        }
        boolean win = r_fight.data.winner == GDFight.Team.A;
        JungleRobReportReq reportReq = new JungleRobReportReq(new RoleSnapshot(role), targetUid, win);
        JungleRobReportRet reportRet = game().pvp.jungle.robReport(reportReq);
        if (reportRet == null) {
            return r.fail("跨服未准备完毕");
        }
        if (!reportRet.r.ok()) {
            return reportRet.r;
        }
        addReport(reportRet.report);
        // 记录次数和奖励
        robTimes++;
        context.reward = reportRet.reward;
        role.getHistory().action.jungleRobTimes();
        return r.success();
    }

    /**
     * 添加战报
     *
     * @param report 战报
     */
    public void addReport(JungleRobReport report) {
        if (reports.size() >= JungleConstants.REPORT_NUM_MAX) {
            int delNum = JungleConstants.REPORT_NUM_MAX - reports.size() + 1;
            reports = new ArrayList<>(reports.subList(delNum, reports.size()));
        }
        reports.add(report);
    }
}
